/*
============================================================================
 Name        : dd_condition.c
 Author      : Jian
 Version     :
 Copyright   : GPL
 Description : dd_condition.c - source file
============================================================================
*/

/* INCLUDE FILES */
#include "dd_condition.h"
#include "dd_util.h"
#include "dd_log.h"

#define wait_lock(cont, l) do { int err = -1; dd_log_sem(l, __FILE__, __LINE__, 1); err = sd_wait_sem(l); __DD_ASSERT_DEFENSE(err >= 0, cont->error = err; return err); } while(0);
#define post_lock(cont, l) do { int err = -1; dd_log_sem(l, __FILE__, __LINE__, 0); err = sd_post_sem(l); __DD_ASSERT_DEFENSE(err >= 0, cont->error = err; return err); } while(0);


dd_condition* dd_cont_create(sd_semp* qLock) 
{
    dd_condition* cont = (dd_condition*)dd_malloc(sizeof(dd_condition)) ;
    
    __DD_CHECK_MEM(cont, sizeof(dd_condition), return NULL) ;

    cont->qLock = qLock ;
    cont->readyLock = sd_create_sem(0) ;

    __DD_ASSERT_DEFENSE(cont->readyLock, NULL) ;
    
    return cont ;
}

void dd_cont_destroy(dd_condition* cont) 
{
    __DD_ASSERT_DEFENSE(cont, return) ;

    dd_cont_signal_all(cont) ;

    sd_destroy_sem(cont->readyLock) ;
    dd_free(cont) ;
}

int dd_cont_wait(dd_condition* cont) 
{
    __DD_ASSERT_DEFENSE(cont, return -1) ;
    
    if (cont->error < 0) 
        return cont->error ;

    cont->waitCount++ ;
    
    post_lock(cont, cont->qLock) ;

    wait_lock(cont, cont->readyLock) ;

    wait_lock(cont, cont->qLock) ;

    return cont->error ;
}

int dd_cont_signal(dd_condition* cont) 
{
    __DD_ASSERT_DEFENSE(cont, return -1) ;

    wait_lock(cont, cont->qLock) ;

    if (cont->error < 0) {
        post_lock(cont, cont->qLock) ;
        return cont->error ;
    }

    if (cont->waitCount > 0) {
        cont->waitCount-- ;
        post_lock(cont, cont->readyLock) ;
    }

    post_lock(cont, cont->qLock) ;

    return cont->error ;
}

int dd_cont_signal_all(dd_condition* cont) 
{
    __DD_ASSERT_DEFENSE(cont, return -1) ;

    wait_lock(cont, cont->qLock) ;

    if (cont->error < 0) {
        post_lock(cont, cont->qLock) ;
        return cont->error ;
    }

    while (cont->waitCount > 0) {
        int err = 0 ;
        cont->waitCount-- ;
        err = sd_post_sem(cont->readyLock) ;
        __DD_ASSERT_DEFENSE(err >= 0, cont->error = err; continue) ;
    }

    post_lock(cont, cont->qLock) ;

    return 0 ;
}

/* End of File */
